package com.mytx.sso.controller;

import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.mytx.common.constant.Constant;
import com.mytx.common.exception.BaseException;
import com.mytx.common.pojo.CommonResult;
import com.mytx.common.pojo.RedisLock;
import com.mytx.common.utils.EntityUtils;
import com.mytx.common.utils.IDUtils;
import com.mytx.mapper.*;
import com.mytx.pojo.*;
import com.mytx.sso.service.ConsumerSearchService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@SuppressWarnings({"SpringJavaInjectionPointsAutowiringInspection", "Duplicates"})
@RestController
public class ForwardController {
    private static Logger logger = LoggerFactory.getLogger(ForwardController.class);

    @Autowired
    DonationMapper donationMapper;
    @Autowired
    ForwardMapper forwardMapper;
    @Autowired
    TopicMapper topicMapper;
    @Autowired
    UserMapper userMapper;
    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    private ConsumerSearchService searchService;

    @Autowired
    MyFileMapper myFileMapper;

    @Autowired
    private HttpServletRequest request;




    /**
     * 转发捐款，只有主题管理员有权限
     * 在此方法中，须判断请求者是否是目标主体的管理员
     *
     * @return
     */
    @Transactional
    @PostMapping("/forwardDonation")
    public CommonResult forwardDonation(@RequestBody Forward forward) {
        String uId = request.getHeader("uId");
        String forwardId = IDUtils.genOrderItemId();
        forward.setfId(forwardId);
        String targetUid = forward.gettId();
        Topic targetTopic;
        String oId = forward.getoId();
        targetTopic = topicMapper.selectByPrimaryKey(oId);
        if (!StringUtils.equals(targetTopic.getManagerId(), uId)) {//判断请求者是否是管理员
            logger.error("转发捐款无权限：uId:{},forward:{}" + uId, forward);
            return CommonResult.build(Constant.DONATION_FORWARD_NO_AUTHORIZATION, "你不是管理员，没有权限");
        }
        BigDecimal forwardAmount = forward.getAmount();
        //检查主题余额是否足够
        if (targetTopic.getDonationBalance().compareTo(forwardAmount) < 0) {
            logger.error("forwardDonation：余额不足,uId:{},forwardAmount:{},donationBalance:{}", uId, forwardAmount, targetTopic.getDonationBalance());

            return CommonResult.build(Constant.BALANCE_NOT_ENOUGH, "余额不足");
        }
        RedisLock lock = new RedisLock(redisTemplate, Constant.TOPIC_DONATION_BALANCE_LOCK + targetTopic.getId());
        try {
            if (!lock.lock()) {
                logger.error("转发捐赠，获取锁失败了" + uId);
                return CommonResult.build(Constant.GET_LOCK_FAIL, "转发捐赠，获取锁失败了");
            }
            boolean isContinue = true;
            int startRow = 0;
            int pageSize = 100;
            BigDecimal currentTotalAmount = BigDecimal.ZERO;
            Date currentDate = new Date();
            boolean isSplitDonation = false;//标记是否对捐赠进行了分拆
            while (isContinue) {
                List<Donation> donations = donationMapper.selectCanForwardDonations(oId, startRow, pageSize);

                if (donations == null || donations.size() == 0) {
                    logger.error("forwardDonation:查询可转发的捐赠为空，forwardAmount：{}，主题剩余捐赠余额：{}", forwardAmount, targetTopic.getDonationBalance());
                    throw new BaseException("没有更多捐赠可以转发了");
                }
                startRow += donations.size();
                List<String> forwardDonationIdList = new ArrayList<>();

                for (Donation donation : donations) {
                    currentTotalAmount = currentTotalAmount.add(donation.getAmount());
                    if (currentTotalAmount.compareTo(forwardAmount) > 0) {//捐赠汇总金额已经超过 转发金额，需要对最后一个捐赠进行分割适配， 跳出循环
                        isContinue = false;
                        isSplitDonation = true;
                        BigDecimal excess = currentTotalAmount.subtract(forwardAmount);//超出的金额
                        Donation childDonation = new Donation();//超出的金额，以原捐赠人的名义生成一个新的捐赠，
                        childDonation.setId(IDUtils.genOrderItemId());
                        childDonation.setoId(oId);
                        childDonation.setParentId(donation.getId());
                        childDonation.setmId(donation.getmId());
                        childDonation.setAmount(excess);
                        childDonation.setStatus(Constant.DONATION_STATUS_COULD_REVOKE);//设置新生成的捐赠状态为可拆回状态
                        childDonation.setType(Constant.DONATION_TYPE_TO_TOPIC);//设置类型为捐赠给 主题类型，因为从是否还有父 捐赠可以得出，这是一个自子捐赠
                        childDonation.setCreated(currentDate);
                        donationMapper.insertSelective(childDonation);
                        BigDecimal originalAmount = donation.getAmount();
                        donation.setAmount(originalAmount.subtract(excess));//更新父捐赠的金额
                        donation.settId(targetUid);
                        donation.setStatus(Constant.DONATION_STATUS_FORWARD);//改变捐赠的状态
                        donation.setfId(forward.getfId());
                        donation.setUpdated(currentDate);
                        donationMapper.updateByPrimaryKeySelective(donation);
                        break;
                    } else if (currentTotalAmount.compareTo(forwardAmount) == 0) {//捐赠汇总的金额与要转发的金额刚好相等，无须对捐赠进行分割适配，跳出循环
                        isContinue = false;
                        forwardDonationIdList.add(donation.getId());
                        break;
                    } else {//捐赠汇总的金额还不足转发金额，需要继续循环，增加汇总金额
                        forwardDonationIdList.add(donation.getId());
                    }
                }

                if (forwardDonationIdList.size() > 0) {
                    DonationExample example = new DonationExample();
                    DonationExample.Criteria criteria = example.createCriteria();
                    criteria.andIdIn(forwardDonationIdList);
                    Donation update = new Donation();
                    update.settId(targetUid);
                    update.setStatus(Constant.DONATION_STATUS_FORWARD);//改变捐赠的状态
                    update.setfId(forward.getfId());
                    update.setUpdated(currentDate);
                    donationMapper.updateByExampleSelective(update, example);
                }
            }
            Topic updateTopic;
            if (isSplitDonation) {
                updateTopic = topicMapper.reduceDonationBalance_V1(forwardAmount, oId);
            } else {
                updateTopic = topicMapper.reduceDonationBalance(forwardAmount, oId);
            }

            User receiver = userMapper.incrementReceivedDonationAmount(forwardAmount, targetUid, currentDate);

            handleFile(forward, uId);
            forward.setManager(uId);//管理员id=经手人 id
            forward.setCreated(currentDate);
            forward.setMyFileList(null);
            forwardMapper.insertSelective(forward);
            //更新到ES
            searchService.update(updateTopic);
            //先判断redis 中是否有 受款人的信息缓存，如果没有，就不管缓存，只对mysql中数据进增加操作
            if (redisTemplate.hasKey(Constant.USER_SESSION + targetUid)) {
                redisTemplate.opsForHash().putAll(Constant.USER_SESSION + targetUid, EntityUtils.objectToMap_v1(receiver));
            }
            logger.info("forwardDonation:转发捐赠，主题捐赠余额减少,topicId:{},forwardId:{}, manager:{},amount:{},转发前的捐赠余额：{}，转后的捐赠余额:{},forwardSize:{}", oId,forwardId, uId, forwardAmount, targetTopic.getDonationBalance(), updateTopic.getDonationBalance(), updateTopic.getForwardSize());
            logger.info("forwardDonation:收到转发捐赠 用户余额增加 uId:{},forwardId:{},amount:{}，balance:{},donationReceived:{}", targetUid,forwardId, forwardAmount, receiver.getBalance(), receiver.getDonationReceived());
            //通过消息队列通知用户收到转发捐赠，app 端应该生成对应的通知信息，并更新用户余额
            JSONObject info = new JSONObject();
            info.put("uId", targetUid);
            info.put("forward", forward);
            redisTemplate.convertAndSend(Constant.NOTIFY_PERSON_RECEIVED_FORWARD, info);

            //返回余额和forwardId
            JSONObject result = new JSONObject();
            result.put("donationBalance", updateTopic.getDonationBalance());
            result.put("forwardId", forward.getfId());
            return CommonResult.ok(result);
        } catch (InterruptedException e) {
            logger.error("forwardDonation：未知错误 e:{}", e);
            return CommonResult.build(Constant.UNKNOWN_ERROR, "未知错误");
        } finally {
            lock.unlock();
        }
    }

    @PostMapping("/queryForwardDonations")
    public CommonResult queryForwardDonations(@RequestBody JSONObject body) {
        String uId = request.getHeader("uId");
        int page = 1;
        int size = 10;
        if (body.containsKey("page")) {
            page = (int) body.get("page");
        }
        if (body.containsKey("size")) {
            size = (int) body.get("size");
        }
        String forwardId = body.getString("forwardId");
        logger.info("queryTopicDonations:查询转赠下的捐赠记录:{}", forwardId);
        PageHelper.startPage(page, size);
        List<Donation> donations = donationMapper.queryForwardDonations(forwardId);
        PageInfo pageInfo = new PageInfo<>(donations);
        for (Donation donation : donations) {
            Boolean member = redisTemplate.opsForSet().isMember("DONATION_PRAISE_RECORD:" + donation.getId(), uId);
            donation.setHasPraise(member);
            Object praiseSize = redisTemplate.opsForValue().get("DONATION_PRAISE_SIZE:" + donation.getId());
            if (praiseSize != null) {
                donation.setPraiseSize((Integer) praiseSize);
            }
        }
        return CommonResult.ok(pageInfo);
    }

    @PostMapping("/loadForwardRecords")
    public CommonResult loadForwardRecords(@RequestBody JSONObject body) {
        String uId = request.getHeader("uId");
        int page = 1;
        int size = 10;
        if (body.containsKey("page")) {
            page = (int) body.get("page");
        }
        if (body.containsKey("size")) {
            size = (int) body.get("size");
        }
        PageHelper.startPage(page, size);
        List<Forward> forwards = forwardMapper.queryReceivedForward(uId);
        PageInfo pageInfo = new PageInfo<>(forwards);
        return CommonResult.ok(pageInfo);
    }

    @PostMapping("/getForwardInfo")
    public CommonResult getForwardInfo(@RequestBody String forwardId) {

        return CommonResult.ok(forwardMapper.queryForward(forwardId));
    }

    @PostMapping("/getForwardInfo_v1")
    public CommonResult getForwardInfo_v1(@RequestBody String forwardId) {

        return CommonResult.ok(forwardMapper.queryForward_v1(forwardId));
    }


    @PostMapping("/accusationForward")
    public CommonResult accusationForward(@RequestBody String forwardId) {
        String uId = request.getHeader("uId");
        logger.info("accusationForward:uid{}   forwardId{}", uId, forwardId);
        Forward forward = new Forward();
        forward.setfId(forwardId);
        forward.setStatus(Constant.TYPE_ACCUSATION);
        forwardMapper.updateByPrimaryKey(forward);
        return CommonResult.ok();
    }

    /**
     * 处理文件
     *
     * @param forward
     * @param uId
     * @return
     */
    private void handleFile(Forward forward, String uId) {
        Date date = new Date();
        List<MyFile> myFileList = forward.getMyFileList();
        List<MyFile> remoteFileList = new ArrayList<>();
        List<String> pictureList = new ArrayList<>();
        for (int i = 0; i < myFileList.size(); i++) {
            MyFile myFile = myFileList.get(i);
            String url = myFile.getUrl();
            if (myFile.getType() == Constant.FILE_TYPE_VIDEO) {
                forward.setVideo(url);
            } else {
                pictureList.add(url);
            }
            if (myFile.getStatus() == Constant.FILE_STATUS_REMOTE) {//为远程文件的，表示已经存储在自己的文件仓库中了，只需更新，不需要再次保存
                myFileList.remove(i);
                myFile.setUpdated(date);
                remoteFileList.add(myFile);//远程文件，需要更新，在更新中增加引用的次数
                i--;
            } else {
                //处理新文件，设置引用次数为第一次，设置创建时间
                myFile.setuId(uId);
                myFile.setStatus(Constant.FILE_STATUS_REMOTE);
                myFile.setReferenceCount(1);//其实这儿也可以在 mysql 建表中设置为默认值为1
                myFile.setCreated(date);
            }
        }
        if (myFileList.size() != 0) {
            myFileMapper.insertBatch(myFileList);
        }
        if (remoteFileList.size() != 0) {
            myFileMapper.updateBatch(remoteFileList);
        }
        if (pictureList.size() != 0) {
            forward.setPictures(pictureList);
        }

    }

}
